package pers.chao.tool.thread.pool.impl;

import pers.chao.tool.http.util.NamedThreadFactory;
import pers.chao.tool.thread.pool.IRealExecutor;

import java.util.Map;
import java.util.concurrent.*;

/**
 * Description: 处理线程执行前和执行后的额外操作
 *
 * @author W.Chao
 * @date 2020/12/13 22:41
 **/
public class RealExecutor extends ThreadPoolExecutor implements IRealExecutor {
	// 保存任务和人物名映射关系
	private final Map<Runnable, String> taskNameMap = new ConcurrentHashMap<>();

	private static final String STATUS_SPLIT = "::";
	private static final String STATUS_RUNNING = "RUNNING";
	private static final String STATUS_RUNNING_ = "RUNNING-";
	private static final String STATUS_IDLE = "IDLE";

	public RealExecutor(int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit unit,
						BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler,
						String prefixName) {
		super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue,
				new NamedThreadFactory(prefixName), handler);
	}

	/**
	 * 任务的执行前处理线程名，用于监控
	 *
	 * @param thread
	 * @param r
	 */
	@Override
	protected void beforeExecute(Thread thread, Runnable r) {
		super.beforeExecute(thread, r);
		String[] nameArray = thread.getName().split(STATUS_SPLIT);

		final String threadName;
		final String taskName = taskNameMap.get(r);
		if (taskName == null) {
			threadName = nameArray[0] + STATUS_SPLIT + STATUS_RUNNING;
		} else {
			threadName = nameArray[0] + STATUS_SPLIT + STATUS_RUNNING_ + taskName;
			synchronized (taskNameMap) {
				taskNameMap.remove(r);
			}
		}

		thread.setName(threadName);
	}

	/**
	 * 任务执行后处理线程名，用于监控
	 *
	 * @param r
	 * @param t
	 */
	@Override
	protected void afterExecute(Runnable r, Throwable t) {
		super.afterExecute(r, t);
		final Thread thread = Thread.currentThread();
		String[] nameArray = thread.getName().split(STATUS_SPLIT);
		thread.setName(nameArray[0] + STATUS_SPLIT + STATUS_IDLE);
	}

	@Override
	public Map<Runnable, String> getTaskNameMap() {
		return taskNameMap;
	}

	@Override
	public String getPrefixName() {
		if (getThreadFactory() instanceof NamedThreadFactory) {
			return ((NamedThreadFactory) getThreadFactory()).getNamePrefix();
		}

		return null;
	}
}
